
#define SERVICE_UUID "0000ffe0-0000-1000-8000-00805f9b34fb"
#define CHARACTERISTIC_UUID "0000ffe1-0000-1000-8000-00805f9b34fb"

boolean doSacn = false;
boolean doConnect = false;
boolean connected = false;

BLEClient *pClient = NULL; // 创建客户端
BLEAdvertisedDevice *pServer;
BLERemoteCharacteristic *pRemoteCharacteristic;

// 搜索到设备时回调功能
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
  void onResult(BLEAdvertisedDevice advertisedDevice)
  {
    // if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(BLEUUID("0000ff11-0000-1000-8000-00805f9b34fb")))
    if (advertisedDevice.haveName() && (advertisedDevice.getName() == "ESP32" || advertisedDevice.getName() == "D30LE_018992"))
    {
      advertisedDevice.getScan()->stop();                  // 停止当前扫描
      pServer = new BLEAdvertisedDevice(advertisedDevice); // 暂存设备
      doSacn = true;
      doConnect = true;
      Serial.println("发现设备");
    }
  }
};

// 客户端与服务器连接与断开回调功能
class MyClientCallback : public BLEClientCallbacks
{
  void onConnect(BLEClient *pclient) {}
  void onDisconnect(BLEClient *pclient)
  {
    ble_U = ble_I = ble_T1 = ble_T2 = ble_IN = ble_OUT = ble_dl = ble_U1 = ble_U2 = ble_U3 = ble_U4 = ble_U1234 = 0.00;
    doConnect = true;
    connected = false;
    Serial.println("蓝牙已断开");
  }
};

void uint8_array_to_hex_string(const uint8_t *array, int length, char *output)
{
  for (int i = 0; i < length; i++)
  {
    sprintf(output + (i * 2), "%02X", array[i]);
  }
}

String charArrayToString(char input[])
{
  String str;
  for (int i = 0; input[i] != '\0'; i++)
  {
    str += input[i];
  }
  return str;
}

void extractMiddleChars(char input[], int start, int length, char output[])
{
  int inputLength = strlen(input);
  int end = start + length - 1;

  if (start < 0 || start >= inputLength || end >= inputLength)
  {
    output[0] = '\0'; // 输入范围错误，返回空字符串
    return;
  }

  int j = 0;
  for (int i = start; i <= end; i++)
  {
    output[j++] = input[i];
  }
  output[j] = '\0'; // 结束字符串
}

float splitString(int a, int b, String input)
{

  String sub = input.substring(a, a + b);
  uint32_t value = strtoul(sub.c_str(), NULL, 16);
  if (b == 8)
  {
    // 将 32 位整数拆分为位
    uint8_t byte0 = (value >> 0) & 0xFF;
    uint8_t byte1 = (value >> 8) & 0xFF;
    uint8_t byte2 = (value >> 16) & 0xFF;
    uint8_t byte3 = (value >> 24) & 0xFF;

    // 按照 IEEE 754 标准进行解码
    union
    {
      float f;
      uint32_t u;
    } conv;

    conv.u = ((uint32_t)byte3 << 24) | ((uint32_t)byte2 << 16) | ((uint32_t)byte1 << 8) | byte0;

    return conv.f;
  }

  return value;
}

// 收到服务推送的数据时的回调函数
void NotifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic, uint8_t *pData, size_t length, bool isNotify)
{
  char hex_string[length * 2 + 1];                      // uint8_t *pData 转为十六进制字符串//length数据长度
  uint8_array_to_hex_string(pData, length, hex_string); // uint8_t * 转为十六进制字符串
  int e = splitString(0, 2, hex_string);
  if (e == 1)
  {
    ble_U = splitString(8, 8, hex_string);
    float ble_I_out = splitString(16, 8, hex_string);
    float ble_I_in = splitString(24, 8, hex_string);
    ble_I = ble_I_in - ble_I_out;
    ble_T1 = splitString(32, 8, hex_string);
    ble_T2 = splitString(40, 8, hex_string);
    ble_IN = splitString(48, 8, hex_string);
    ble_OUT = splitString(56, 8, hex_string);
    ble_dl = splitString(76, 4, hex_string);
  }
  else if (e == 2)
  {
    ble_U1 = splitString(48, 8, hex_string);
    ble_U2 = splitString(56, 8, hex_string);
    ble_U3 = splitString(64, 8, hex_string);
    ble_U4 = splitString(72, 8, hex_string);
    ble_U1234 = (ble_U1 + ble_U2 + ble_U3 + ble_U4) / 4;
  }
  else if (e == 3)
  {
    Serial.println(e);
  }
}

// 用来连接设备获取其中的服务与特征
bool ConnectToServer(void)
{
  pClient = BLEDevice::createClient();                 // 创建客户端
  pClient->setClientCallbacks(new MyClientCallback()); // 添加客户端与服务器连接与断开回调功能
  if (!pClient->connect(pServer))
  { // 尝试连接设备
    return false;
  }
  Serial.println("连接设备成功");

  BLERemoteService *pRemoteService = pClient->getService(SERVICE_UUID); // 尝试获取设备中的服务
  if (pRemoteService == nullptr)
  {
    Serial.println("获取服务失败");
    pClient->disconnect();
    return false;
  }
  Serial.println("获取服务成功");
  Serial.println("获取服务成功");

  pRemoteCharacteristic = pRemoteService->getCharacteristic(CHARACTERISTIC_UUID); // 尝试获取服务中的特征
  if (pRemoteCharacteristic == nullptr)
  {
    Serial.println("获取特性失败");
    pClient->disconnect();
    return false;
  }
  Serial.println("获取特征成功");
  Serial.println("获取服务成功");

  if (pRemoteCharacteristic->canRead())
  { // 如果特征值可以读取则读取数据
    Serial.printf("该特征值可以读取并且当前值为: %s\r\n", pRemoteCharacteristic->readValue().c_str());
  }
  if (pRemoteCharacteristic->canNotify())
  { // 如果特征值启用了推送则添加推送接收处理
    pRemoteCharacteristic->registerForNotify(NotifyCallback);
  }
  return true;
}

void initble()
{
  BLEDevice::init("");
  BLEScan *pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->setInterval(100);
  pBLEScan->setWindow(80);
}
unsigned long BleTick = 0; // 心跳
int b = 10;
String hexCommand;

void qidongble()
{
  if (!ble)
  {
    if (connected)
    {
      Serial.println("断开蓄电池......");
      pClient->disconnect();
      doConnect = true;
      connected = false;
    }
    // if ((millis() - BleTick >= 60000))
    // {
    //   ble = true;
    // }
  }
  if (ble && millis() - BleTick >= 2000)
  {
    // 如果需要扫描则进行扫描
    if (!doSacn)
    {
      Serial.println("搜索蓄电池......");
      BLEDevice::getScan()->clearResults();
      BLEDevice::getScan()->start(1); // 持续搜索设备
    }
    // 如果找到设备就尝试连接设备
    if (doConnect)
    {
      if (ConnectToServer())
      {
        connected = true;
      }
      else
      {
        doSacn = false;
      }
      doConnect = false;
    }
    // 如果已经连接就可以向设备发送数据
    if (connected)
    {
      if (pRemoteCharacteristic->canWrite())
      {
        // 如果可以向特征值写数据
        // 要发送的 16 进制命令字符串
        if (b < 10)
        {
          b++;
          hexCommand = "197001000188097078"; // c5 01 00 bc 61 4e 第一页读取代码
        }
        else
        {
          b = 0;
          hexCommand = "091002000188097078"; // 5b 02 00 bc 61 4e 第二页读取代码
        }

        // hexCommand = "086086000188097078";    // 56 56 00 bc 61 4e 设置读取代码
        // 将字符串转换为字节数组
        byte commandBytes[hexCommand.length() / 3];

        for (int i = 0; i < hexCommand.length() / 3; i++)
        {
          int hexValue = hexCommand.substring(i * 3, i * 3 + 3).toInt();
          commandBytes[i] = hexValue;
        }
        pRemoteCharacteristic->writeValue(commandBytes, hexCommand.length() / 3);
      }
    }
    BleTick = millis();
  }
}
